package com.ozo.boot.manage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ozo.boot.common.base.constant.CommonConstant;
import com.ozo.boot.common.base.constant.ConfigTypeEnum;
import com.ozo.boot.common.base.model.BasePage;
import com.ozo.boot.common.base.model.BaseBatchDTO;
import com.ozo.boot.common.base.model.PageResult;
import com.ozo.boot.common.core.exception.ServiceException;
import com.ozo.boot.common.database.util.SortUtils;
import com.ozo.boot.manage.exception.ManageExceptionEnum;
import com.ozo.boot.manage.pojo.dto.ChangeStatusDTO;
import com.ozo.boot.manage.pojo.dto.SysRolePermissionDTO;
import com.ozo.boot.manage.pojo.dto.SysRoleQueryDTO;
import com.ozo.boot.manage.pojo.dto.SysRoleSaveDTO;
import com.ozo.boot.manage.entity.SysRole;
import com.ozo.boot.manage.entity.SysRolePermissionRel;
import com.ozo.boot.manage.entity.SysUserRoleRel;
import com.ozo.boot.manage.mapper.SysRoleMapper;
import com.ozo.boot.manage.pojo.vo.SysRoleVO;
import com.ozo.boot.manage.service.ISysRolePermissionRelService;
import com.ozo.boot.manage.service.ISysRoleService;
import com.ozo.boot.manage.service.ISysUserRoleRelService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色 服务实现类
 * </p>
 *
 * @author qiangesoft
 * @since 2024-07-11
 */
@RequiredArgsConstructor
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {

    private final ISysUserRoleRelService sysUserRoleRelService;

    private final ISysRolePermissionRelService sysRolePermissionRelService;

    @Override
    public void add(SysRoleSaveDTO saveDTO) {
        // 参数校验
        this.checkParam(null, saveDTO.getRoleName(), saveDTO.getRoleCode());

        SysRole sysRole = BeanUtil.copyProperties(saveDTO, SysRole.class);
        sysRole.setRoleType(ConfigTypeEnum.CUSTOM.getCode());
        baseMapper.insert(sysRole);
    }

    /**
     * 合法性校验
     *
     * @param id
     * @param roleName
     * @param roleCode
     */
    private void checkParam(Long id, String roleName, String roleCode) {
        LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysRole::getRoleName, roleName)
                .ne(Objects.nonNull(id), SysRole::getId, id);
        Long count = baseMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new ServiceException(ManageExceptionEnum.ROLE_NAME_EXISTS);
        }

        LambdaQueryWrapper<SysRole> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(SysRole::getRoleCode, roleCode)
                .ne(Objects.nonNull(id), SysRole::getId, id);
        Long count1 = baseMapper.selectCount(queryWrapper1);
        if (count1 > 0) {
            throw new ServiceException(ManageExceptionEnum.ROLE_CODE_EXISTS);
        }
    }

    @Override
    public void remove(BaseBatchDTO<Long> batchDTO) {
        baseMapper.deleteBatchIds(batchDTO.getIdList());
    }

    @Override
    public void edit(SysRoleSaveDTO saveDTO) {
        // 参数校验
        this.checkParam(saveDTO.getId(), saveDTO.getRoleName(), saveDTO.getRoleCode());

        SysRole sysRole = BeanUtil.copyProperties(saveDTO, SysRole.class);
        baseMapper.updateById(sysRole);
    }

    @Override
    public PageResult<SysRoleVO> page(BasePage basePage, SysRoleQueryDTO queryDTO) {
        Integer pageNum = basePage.getPageNum();
        Integer pageSize = basePage.getPageSize();

        QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
        // 排序
        String order = basePage.getOrder();
        if (StrUtil.isBlank(order)) {
            queryWrapper.lambda().orderByDesc(SysRole::getId);
        } else {
            SortUtils.setSortCondition(queryWrapper, basePage.getProp(), order);
        }
        // 条件
        queryWrapper.lambda()
                .like(StrUtil.isNotBlank(queryDTO.getRoleName()), SysRole::getRoleName, queryDTO.getRoleName())
                .eq(StrUtil.isNotBlank(queryDTO.getStatus()), SysRole::getStatus, queryDTO.getStatus());
        Page<SysRole> page = baseMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper);

        PageResult<SysRoleVO> pageResult = new PageResult<>();
        pageResult.setPageNum(pageNum);
        pageResult.setPageSize(pageSize);
        pageResult.setPage(page.getPages());
        pageResult.setTotal(page.getTotal());
        List<SysRole> records = page.getRecords();
        if (CollUtil.isEmpty(records)) {
            pageResult.setResults(List.of());
            return pageResult;
        }

        List<SysRoleVO> recordVOList = BeanUtil.copyToList(records, SysRoleVO.class);
        pageResult.setResults(recordVOList);
        return pageResult;
    }

    @Override
    public List<SysRoleVO> listAll() {
        List<SysRole> sysRoleList = this.list();
        return BeanUtil.copyToList(sysRoleList, SysRoleVO.class);
    }

    @Override
    public void changeStatus(ChangeStatusDTO statusDTO) {
        LambdaUpdateWrapper<SysRole> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(SysRole::getId, statusDTO.getId())
                .set(SysRole::getStatus, statusDTO.getStatus());
        baseMapper.update(updateWrapper);
    }

    @Override
    public SysRolePermissionDTO getPermission(Long id) {
        SysRole sysRole = baseMapper.selectById(id);

        SysRolePermissionDTO sysRolePermissionDTO = new SysRolePermissionDTO();

        // 菜单权限
        List<Long> permissionIdList = sysRolePermissionRelService.getPermissionIdListByRoleId(id);
        sysRolePermissionDTO.setMenuIdList(permissionIdList);

        // 数据权限
        sysRolePermissionDTO.setDataScope(sysRole.getDataScope());
        List<String> dataScopeDeptIds = StrUtil.split(sysRole.getDataScopeDeptIds(), CommonConstant.COMMA);
        List<Long> deptIdList = new ArrayList<>();
        for (String deptId : dataScopeDeptIds) {
            deptIdList.add(Long.parseLong(deptId));
        }
        sysRolePermissionDTO.setDeptIdList(deptIdList);
        return sysRolePermissionDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void savePermission(SysRolePermissionDTO rolePermissionDTO) {
        Long roleId = rolePermissionDTO.getRoleId();
        String dataScope = rolePermissionDTO.getDataScope();
        List<Long> deptIdList = rolePermissionDTO.getDeptIdList();
        if ("5".equals(dataScope) && CollUtil.isEmpty(deptIdList)) {
            throw new ServiceException(ManageExceptionEnum.CUSTOM_DATA_SCOPE_DEPT_NOT_EMPTY);
        }
        SysRole sysRole = baseMapper.selectById(roleId);
        if (sysRole == null) {
            throw new ServiceException(ManageExceptionEnum.ROLE_NOT_EXISTS);
        }

        // 数据权限
        LambdaUpdateWrapper<SysRole> roleUpdateWrapper = new LambdaUpdateWrapper<>();
        String dataScopeDeptIds = CollUtil.isEmpty(deptIdList) ? null : CollUtil.join(deptIdList, CommonConstant.COMMA);
        roleUpdateWrapper.eq(SysRole::getId, sysRole.getId())
                .set(SysRole::getDataScope, dataScope)
                .set(SysRole::getDataScopeDeptIds, dataScopeDeptIds);
        baseMapper.update(sysRole, roleUpdateWrapper);

        // 菜单权限
        LambdaQueryWrapper<SysRolePermissionRel> relQueryWrapper = new LambdaQueryWrapper<>();
        relQueryWrapper.eq(SysRolePermissionRel::getRoleId, roleId);
        sysRolePermissionRelService.remove(relQueryWrapper);

        List<Long> menuIdList = rolePermissionDTO.getMenuIdList();
        List<SysRolePermissionRel> rolePermissionRelList = new ArrayList<>();
        for (Long menuId : menuIdList) {
            SysRolePermissionRel rolePermissionRel = new SysRolePermissionRel();
            rolePermissionRel.setRoleId(roleId);
            rolePermissionRel.setPermissionId(menuId);
            rolePermissionRelList.add(rolePermissionRel);
        }
        sysRolePermissionRelService.saveBatch(rolePermissionRelList);
    }

    @Override
    public List<Long> listRoleIdListByUserId(Long userId) {
        List<SysUserRoleRel> userRoleRelList = sysUserRoleRelService.lambdaQuery().eq(SysUserRoleRel::getUserId, userId).list();
        return userRoleRelList.stream().map(SysUserRoleRel::getRoleId).collect(Collectors.toList());
    }

    @Override
    public List<SysRoleVO> listByUserId(Long userId) {
        List<Long> roleIdList = this.listRoleIdListByUserId(userId);
        if (roleIdList.isEmpty()) {
            return List.of();
        }

        List<SysRole> sysRoleList = baseMapper.selectBatchIds(roleIdList);
        return BeanUtil.copyToList(sysRoleList, SysRoleVO.class);
    }

    @Override
    public Map<Long, List<SysRoleVO>> listByUserIds(List<Long> userIdList) {
        List<SysUserRoleRel> userRoleRelList = sysUserRoleRelService.lambdaQuery().in(SysUserRoleRel::getUserId, userIdList).list();
        Map<Long, List<SysUserRoleRel>> groupRoleMap = userRoleRelList.stream().collect(Collectors.groupingBy(SysUserRoleRel::getUserId));
        Set<Long> roleIdSet = userRoleRelList.stream().map(SysUserRoleRel::getRoleId).collect(Collectors.toSet());

        Map<Long, List<SysRoleVO>> roleMap = new HashMap<>();
        if (roleIdSet.isEmpty()) {
            return roleMap;
        }

        List<SysRole> sysRoleList = baseMapper.selectBatchIds(roleIdSet);
        List<SysRoleVO> sysRoleVOList = BeanUtil.copyToList(sysRoleList, SysRoleVO.class);

        for (Long userId : userIdList) {
            List<SysUserRoleRel> roleRelList = groupRoleMap.get(userId);
            if (CollUtil.isNotEmpty(roleRelList)) {
                Set<Long> roleIds = roleRelList.stream().map(SysUserRoleRel::getRoleId).collect(Collectors.toSet());
                List<SysRoleVO> roleVOList = sysRoleVOList.stream().filter(e -> roleIds.contains(e.getId())).collect(Collectors.toList());
                roleMap.put(userId, roleVOList);
            } else {
                roleMap.put(userId, List.of());
            }
        }
        return roleMap;
    }

}
